#pragma once
#include <iostream>
#include <functional>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <memory>
#include "InetAddr.hpp"
#include "Log.hpp"
#include "Common.hpp"
#include "ThreadPool.hpp"
#include "Task.hpp"
using namespace my_log;
using namespace my_threadpool;
using func_t = function<void()>;
using func_task = function<void(int socketfd, InetAddr addr)>;
static const int backlog = 8;
void fun()
{
    LOG(Level::INFO)<<"fun-";
    while(1)
    {
    }
}
class TcpServer : public NoCopy
{
private:
    void Server(int socketfd, InetAddr addr)
    {
        while (_isrunning)
        {
            char buffer[1024];
            int n = read(socketfd, buffer, sizeof(buffer));
            if (n < 0)
            {
                LOG(Level::WARING) << "read fail";
                close(socketfd);
                break;
            }
            else if (n = 0)
            {
                LOG(Level::INFO) << "client exit";
                close(socketfd);
                break;
            }
            else
            {
                buffer[n] = '\0';
                LOG(Level::INFO) << addr.stringaddr() << "#" << buffer;
                // 回调处理
                string echo_string = addr.stringaddr();
                // 处理结果写回客户端
                write(socketfd, echo_string.c_str(), sizeof(echo_string));
            }
        }
    }
    static void *Routine(void *data)
    {
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(data);
        td->_ts->Server(td->_socketfd, td->_socketfd);
        close(td->_socketfd);
        exit(SUCCESS);
        return nullptr;
    }

public:
    TcpServer(uint16_t port, func_t func)
        : _port(port), _listenfd(-1), _func(func), _isrunning(false)
    {
    }
    void Init()
    {
        // 套接字文件
        _listenfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listenfd < 0)
        {
            LOG(Level::FATAL) << "listen socket fial";
            exit(SOCKET_ERRO);
        }
        LOG(Level::INFO) << "listen socket success";

        // 绑定端口
        InetAddr addr(_port);
        int n = bind(_listenfd, addr.getaddr(), addr.getlen());
        if (n < 0)
        {
            LOG(Level::FATAL) << "bind fail";
            exit(BIND_ERRO);
        }
        LOG(Level::INFO) << "bind success";

        // 打开监听
        n = listen(_listenfd, backlog);
        if (n < 0)
        {
            LOG(Level::FATAL) << "listen fail";
            exit(LISTEN_ERRO);
        }
        LOG(Level::INFO) << "open success";
    }
    class ThreadData
    {
    public:
        ThreadData(int socketfd, InetAddr addr, TcpServer *ts)
            : _socketfd(socketfd), _addr(addr), _ts(ts)
        {
        }
        int _socketfd;
        InetAddr _addr;
        TcpServer *_ts;
    };
    void Run()
    {
        _isrunning = true;
        while (_isrunning)
        {
            InetAddr addr(_port);
            socklen_t len = addr.getlen();
            LOG(Level::INFO)<<"wait...";
            int socketfd = accept(_listenfd, addr.getaddr(), &len);
            if (socketfd < 0)
            {
                LOG(Level::WARING) << "accept fail";
                exit(ACCEPT_ERRO);
            }
            LOG(Level::INFO) << "accept success addr:" << addr.stringaddr();
#if 0
            //单线程
            Server(socketfd, addr);
            //多进程(长服务)
            pid_t pid = fork();
            if(pid < 0)
            {
                LOG(Level::FATAL)<<"fork fail";
                exit(FORK_ERRO);
            }
            else if(pid == 0)
            {
                close(_listenfd);
                if(fork() > 0)
                    exit(SUCCESS);
                Server(socketfd,addr);
                exit(SUCCESS);
            }
            else
            {
                close(socketfd);
            }
#endif
            // 多线程(长服务)
             pthread_t tid;
             ThreadData *data = new ThreadData(socketfd, addr, this); // InetAddr(){}?
             pthread_create(&tid, nullptr, Routine, (void *)data);
            
            //线程池(短服务)
            // ThreadPool<func_t>::GetTreadPool()->Push([&]()
            //                                          { this->Server(socketfd, addr); });
            //ThreadPool<task_t>::GetTreadPool()->Push(Download);
            //sleep(1);
        }
        _isrunning = false;
    }

private:
    uint16_t _port;
    int _listenfd;
    func_t _func;
    bool _isrunning;
};
